from broker.tws.constant.Constant import *

class RET:
    def __init__(self, code: int = RetCode.OK):
        self.code = code
        self.msg = ""

    def __str__(self):
        return "%s" % [self.code, self.msg]

    def ok(self, code: int = RetCode.OK):
        self.code = code
        self.msg = ""

    def error(self, code: int = RetCode.ERROR, msg: str = ""):
        self.code = code
        self.msg = msg


class Tickle:
    def __init__(self):
        self.session = ""
        self.userId = 0
        self.collission = False
        self.authenticated = False
        self.competing = False
        self.connected = False

    def __str__(self):
        return "%s" % [self.session, self.userId, self.collission, self.authenticated, self.competing, self.connected]

    @staticmethod
    def parse(result: dict):
        tickle = Tickle()
        tickle.session = result["session"]
        tickle.userId = result["userId"]
        tickle.collission = result["collission"]

        authStatus = result["iserver"]["authStatus"]
        tickle.authenticated = authStatus["authenticated"]
        tickle.competing = authStatus["competing"]
        tickle.connected = authStatus["connected"]
        return tickle


class LiveOrder:
    def __init__(self):
        self.orderId = 0   # Order identifier
        self.account = ""   # 交易账号
        self.conid = 0     # Contract identifier
        self.secType = SecType.STK  # Asset class
        self.side = Side.BUY   # 交易买卖方向
        self.orderType = OrderType.LMT
        self.price = 0.0    # 委托价
        self.quantity = 0   # 委托数量
        self.timeInForce = TimeInForce.DAY
        self.filledQuantity = 0  # Quantity filled
        self.remainingQuantity = 0  # Quantity remaining
        self.status = OrderStatus.PRE_SUBMITTED   # Status of the order, eg: "inactive" "submitted" "filled" "cancelled"

    def __str__(self):
        return "%s" % [self.orderId, self.ctime, self.price, self.amount, self.type, self.contractType, self.status]

    @staticmethod
    def parse(result: list):
        orders = list()
        for item in result:
            order = LiveOrder()
            order.orderId = item["orderId"]
            order.account = item["acct"]
            order.conid = item["conid"]
            order.secType = item["secType"]
            order.side = item["side"]
            order.orderType = item["orderType"]
            order.price = float(item["price"])
            order.filledQuantity = item["filledQuantity"]
            order.remainingQuantity = item["remainingQuantity"]
            order.quantity = order.filledQuantity + order.remainingQuantity
            order.status = item["status"]
            orders.append(order)
        return orders


class POrder:

    def __init__(self):
        self.pid = ""
        self.message = ""
        self.messageIds = ""
        self.isSuppressed = False

        self.order_id = ""   # Order identifier
        self.local_order_id = ""   # Order identifier
        # Status of the order, eg: "inactive" "submitted" "filled" "cancelled"
        self.order_status = OrderStatus.PRE_SUBMITTED   # 交易账号

    def __str__(self):
        return "%s" % [self.pid, self.messageIds, self.order_id, self.local_order_id, self.order_status]

    @staticmethod
    def parse_place(result):
        porder = POrder()
        result = result[0]
        porder.pid = result["id"]
        porder.message = result["message"]
        porder.messageIds = result["messageIds"]
        return porder

    def parse_reply(self, result: dict):
        self.order_id = result["order_id"]
        self.local_order_id = result["local_order_id"]
        self.order_status = result["order_status"]


class AccountSummary:

    def __init__(self):
        self.availablefunds = 0.0
        self.buyingpower = 0.0      # 最大购买力
        self.guarantee = 0.0
        self.leverage = 0.0
        self.initmarginreq = 0.0    # 初始保证金
        self.maintmarginreq = 0.0   # 维持保证金
        self.fullmaintmarginreq = 0.0   #
        self.netliquidation = 0.0   # 资产净值
        self.grosspositionvalue = 0.0
        self.highestseverity = 0.0
        self.lookaheadavailablefunds = 0.0
        self.fullavailablefunds = 0.0

    def __str__(self):
        return "%s" % [self.availablefunds, self.buyingpower, self.guarantee, self.maintmarginreq, self.netliquidation]

    @staticmethod
    def parse(result: dict):
        summary = AccountSummary()
        for key in result:
            if key == "availablefunds":
                summary.availablefunds = result[key]["amount"]
            elif key == "buyingpower":
                summary.buyingpower = result[key]["amount"]
            elif key == "guarantee":
                summary.guarantee = result[key]["amount"]
            elif key == "leverage":
                summary.leverage = result[key]["amount"]
            elif key == "initmarginreq":
                summary.initmarginreq = result[key]["amount"]
            elif key == "maintmarginreq":
                summary.maintmarginreq = result[key]["amount"]
            elif key == "fullmaintmarginreq":
                summary.fullmaintmarginreq = result[key]["amount"]
            elif key == "netliquidation":
                summary.netliquidation = result[key]["amount"]
            elif key == "grosspositionvalue":
                summary.grosspositionvalue = result[key]["amount"]
            elif key == "highestseverity":
                summary.highestseverity = result[key]["amount"]
            elif key == "lookaheadavailablefunds":
                summary.lookaheadavailablefunds = result[key]["amount"]
            elif key == "fullavailablefunds":
                summary.fullavailablefunds = result[key]["amount"]
        return summary


class AccountLedger:

    def __init__(self):
        self.cashbalance = 0.0      # 现金余额
        self.stockmarketvalue = 0.0     # 股票市值
        self.realizedpnl = 0.0      # 已实现盈亏
        self.unrealizedpnl = 0.0    # 未实现盈亏
        self.stockoptionmarketvalue = 0.0
        self.settledcash = 0.0

    def __str__(self):
        return "%s" % [self.cashbalance, self.stockmarketvalue, self.realizedpnl, self.unrealizedpnl]

    @staticmethod
    def parse(result: dict):
        ledger = AccountLedger()
        base = result["BASE"]
        ledger.cashbalance = base["cashbalance"]
        ledger.stockmarketvalue = base["stockmarketvalue"]
        ledger.realizedpnl = base["realizedpnl"]
        ledger.unrealizedpnl = base["unrealizedpnl"]
        ledger.settledcash = base["settledcash"]
        return ledger


class Contract:

    def __init__(self):
        self.conid = 0
        self.symbol = ""     # Underlying symbol
        self.opt = ""      # List of Option expirations in YYYYMMDD format separated by semicolon
        self.companyName = ""

    def __str__(self):
        return "%s" % [self.conid, self.symbol, self.companyName, self.opt]

    @staticmethod
    def parse(result: list):
        result = result[0]
        cont = Contract()
        cont.conid = result["conid"]
        cont.symbol = result["symbol"]
        cont.opt = result["opt"]
        cont.companyName = result["companyName"]
        return cont


class PreOrder:

    def __init__(self):
        self.price = 0.0
        self.amount = 0.0   # 金额
        self.quantity = 0    # 数量
        self.marginLevel = 0.0     # 交易放大杠杆
        self.initmarginreq = 0.0    # 初始保证金
        self.maintmarginreq = 0.0      # 维持保证金
        self.commission = ""    # 交易佣金

    def __str__(self):
        return "%s" % [self.price, self.amount, self.quantity, self.marginLevel, self.initmarginreq, self.maintmarginreq, self.commission]

    @staticmethod
    def parse(result: dict, price: float = None):
        preOrder = PreOrder()
        preOrder.price = price
        amount = result["amount"]
        preOrder.amount = amount["amount"]
        preOrder.commission = amount["commission"]
        equity = result["equity"]
        initial = result["initial"]
        preOrder.initmarginreq = float(initial["change"].replace(",", ""))
        maintenance = result["maintenance"]
        preOrder.maintmarginreq = maintenance["change"]

        position = result["position"]
        preOrder.quantity = float(position["change"])

        if price and preOrder.initmarginreq:
            preOrder.marginLevel = preOrder.price * preOrder.quantity / preOrder.initmarginreq
        return preOrder


class OrderStatus:

    def __init__(self):
        self.order_id = 0
        self.conid = 0
        self.symbol = ""    # 交易对
        self.side = SideAbbr.BUY    # 方向

        self.orderType = OrderType.LMT
        self.totalSize = 0    #
        self.filledSize = 0
        self.averagePrice = 0.0   # 均价
        self.orderTime = ""   # 格式： "211109085033"
        self.secType = SecType.STK   #
        self.tif = 0    # 可平数量(张数）
        self.account = ""

    def __str__(self):
        return "%s" % [self.symbol, self.type, self.avgPrice, self.amount, self.marginLevel, self.availAmount]

    @staticmethod
    def parse(result: list):
        positions = list()
        for item in result:
            p = OrderStatus()
            p.symbol = item["symbol"]
            p.type = item["type"]
            p.avgPrice = float(item["open_price_avg"])
            p.amount = float(item["amount"])
            p.marginLevel = item["lever_rate"]
            p.availAmount = float(item["avail_amount"])
            positions.append(p)
        return positions


class Trade:

    def __init__(self):
        self.symbol = ""    # 交易对
        self.side = SideAbbr.B    # 方向
        self.trade_time = 0   # 时间戳
        self.price = 0.0   # 价格
        self.size = 0   # 数量
        self.order_ref = ""     # 自定义订单号
        self.exchange = ""
        self.listing_exchange = ""
        self.net_amount = 0
        self.account = ""
        self.secType = ""
        self.commission = 0.0


    def __str__(self):
        return "%s" % [self.symbol, self.side, self.trade_time, self.price, self.size,
                       self.exchange, self.secType, self.listing_exchange, self.commission]

    @staticmethod
    def parse(result: list):
        trades = list()
        if not result:
            return trades
        for item in result:
            trade = Trade()
            trade.symbol = item["symbol"]
            trade.side = item["side"]
            trade.price = float(item["price"])
            trade.size = item["size"]
            trade.order_ref = item["order_ref"]
            trade.exchange = item["exchange"]
            trade.listing_exchange = item["listing_exchange"]
            trade.net_amount = item["net_amount"]
            trade.account = item["account"]
            trade.secType = item["sec_type"]
            trade.commission = item["commission"]
            trades.append(trade)
        return trades